package org.ethereum.net.dpos;

import java.math.BigInteger;

import org.ethereum.core.BlockHeader;
import org.ethereum.net.rlpx.Node;
import org.ethereum.net.server.ChannelManager;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.spongycastle.util.encoders.Hex;

public class PackageResponse extends DPOSMessage {

	private Node electionNode;
	
	private final BlockHeader newBlockHeader;

	private final long round;

	private final byte[] presidentId;

	private final byte[] electionId;

	public PackageResponse(final byte[] encoded) {
		super(encoded);
		RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
		this.responseCode = ResponseCode.code(RLP.decodeInt(paramsList.get(0).getRLPData(), 0));
		this.round = new BigInteger(1, paramsList.get(1).getRLPData()).longValue();
		if (round < 1) {
	    		throw new IllegalArgumentException("round must be greater then from 1!");
	    }
		this.presidentId = paramsList.get(2).getRLPData();
		this.electionId = paramsList.get(3).getRLPData();
		if (responseCode == ResponseCode.SUCCESS) {
			this.newBlockHeader = new BlockHeader(paramsList.get(4).getRLPData());
		} else {
			this.newBlockHeader = null;
		}
		this.parsed = true;
	}

	public PackageResponse(BlockHeader newBlock, final long round, final byte[] presidentId,
			byte[] electionId, ResponseCode code) {
		super(newBlock != null ? newBlock.getEncoded() : null);
		this.newBlockHeader = newBlock;
		if (round < 1) {
	    		throw new IllegalArgumentException("round must be greater then 1!");
	    }
		this.round = round;
		this.presidentId = presidentId;
		this.electionNode = null;
		this.electionId = electionId;
		this.responseCode = code;
		
		encode();
	}

	private void encode() {
		byte[] responseCode = RLP.encodeInt(this.responseCode.getCode());
		byte[] round = RLP.encodeBigInteger(BigInteger.valueOf(this.round));
		byte[] presidentId = RLP.encodeElement(this.presidentId);
		byte[] electionId = RLP.encodeElement(this.electionId);
		if (this.newBlockHeader != null) {
			this.encoded = RLP.encodeList(responseCode, round, presidentId, electionId, this.encoded);
		} else {
			this.encoded = RLP.encodeList(responseCode, round, presidentId, electionId);
		}
		this.parsed = true;
	}
	
	public Node getElectionNodeInfo(ChannelManager manager) {
		if (electionNode == null) {
			electionNode = manager.getNodeById(this.electionId);
		}
		return electionNode;
	}

	public long getRound() {
		return round;
	}

	public byte[] getPresidentId() {
		return presidentId;
	}
	
	public byte[] getElectionId() {
		return electionId;
	}
	
	public BlockHeader getBlockHeader() {
		return newBlockHeader;
	}

	@Override
	public DPOSMessageCodes getCommand() {
		return DPOSMessageCodes.PACKAGE_RESPONSE;
	}

	@Override
	public byte[] getEncoded() {
		return this.encoded;
	}

	@Override
	public Class<?> getAnswerMessage() {
		return null;
	}

	@Override
	public String toString() {
		return "{round: "+round+", presidentId: "+ Hex.toHexString(presidentId)
				+", electionId: "+ Hex.toHexString(electionId)+", responseCode: "+responseCode.toString()+" }";
	}

}
